#include "file-list.h"
#include "message.h"
#include "log.h"

FileList::File::File(const QByteArray& name,
                     const FingerPrint& fingerprint,
                     quint32 size) :
    name_(name), fingerprint_(fingerprint), size_(size) {
}

FileList::File* FileList::File::clone() const {
    return new File(name_, fingerprint_, size_);
}

void FileList::read_from_xml(const std::string &filepath){
	xmlDoc *doc = NULL;
    xmlNode *root_element = NULL;
    /*
     * this initialize the library and check potential ABI mismatches
     * between the version it was compiled for and the actual shared
     * library used.
     */
    LIBXML_TEST_VERSION

    /*parse the file and get the DOM */
    doc = xmlReadFile(filepath.c_str(), NULL, 0);

	CHECK_NE(doc, NULL)
		<< "Could not parse file " << filepath;
    
    /*Get the root element node */
    root_element = xmlDocGetRootElement(doc);
    
	CHECK_EQ(0, strcmp((const char*)root_element->name, "filelist"))
		<< "The filelist XML file contains a strange node for root:"<< root_element->name ;
	
    for (xmlNode *cur_node = root_element->children; cur_node; cur_node = cur_node->next) {
    	CHECK_EQ(0, strcmp((const char*)cur_node->name, "file"))
			<< "The filelist XML file contains a strange node :"<< cur_node->name ;
		File *file = new File;
					
		xmlNode *element = cur_node->children;
		const QByteArray name = QByteArray((char*)element->content);
		file->set_name(name);		
		element = element->next;
		file->set_size(atoi((const char*)element->content));
		element = element->next;
		FingerPrint finger = FingerPrint();
		QByteArray signature = QByteArray((const char*)element->content);
		for (int i=0; i<signature.length(); i++){
			finger.set_signature(i, signature.at(i) );
		}
		file->set_fingerprint(finger);
		element = element->next;
		std::vector<FingerPrint> fingers = std::vector<FingerPrint>();
		while( element ){
			FingerPrint f = FingerPrint();
			QByteArray sig = QByteArray((const char*)element->content);
			for (int i=0; i<sig.length(); i++){
				f.set_signature(i, sig.at(i) );
			}
			fingers.push_back(f);
			element = element->next;			
		}
		file->set_fingers(fingers);
		push_back(file);
    }

	/*free the document */
    xmlFreeDoc(doc);
    
    /*
     *Free the global variables that may
     *have been allocated by the parser.
     */
    xmlCleanupParser();	
}

void FileList::write_to_xml(const std::string &filepath){
	FILE *file = fopen(filepath.c_str(), "w");
	CHECK_NE(file,NULL) << "Could not open file to write the filelist.";
	
	fprintf(file,"%s","<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n");
	fprintf(file,"%s","<filelist>\n");
	for (int i=0; i<(int)list_.size(); i++){
		fprintf(file,"<file>\n");
		fprintf(file,"<name>%s</name>\n",list_.at(i)->name().data() );
		fprintf(file,"<size>%i</size>\n",list_.at(i)->size() );
		fprintf(file,"<hash>");
		QByteArray signature = QByteArray();
		for (int k=0; k<16; k++) signature.append(list_.at(i)->fingerprint().signature(k));
		fprintf(file,"%s</hash>\n",signature.data());
		for (int j=0; j<(int)list_.at(i)->fingers().size();j++){
			fprintf(file,"<hash>");
			QByteArray sig = QByteArray();
			for (int k=0; k<16; k++) 
				signature.append(list_.at(i)->fingers().at(j).signature(k));
			fprintf(file,"%s</hash>\n",sig.data());			
		}		
		fprintf(file,"</file>\n");
	}
	fprintf(file,"</filelist>");
	fclose(file);
}


void FileList::File::append(QByteArray* array) const {
    messages::ByteArrayAppender a(array);
    a.append(name_);
    a.append(fingerprint_);
    a.append(size_);
}

void FileList::File::parse(const QByteArray* array, int* position) {
    messages::ByteArrayParser p(array, position);
    p.parse(&name_);
    p.parse(&fingerprint_);
    p.parse(&size_);
}

FileList::~FileList() {
    for (int i = 0; i < (int)list_.size(); ++i)
        delete list_[i];
}
